import { nGet } from "../request";
import * as vscode from "vscode";
import {
  showInformationMessage,
  showErrorMessage,
  openDiffMsg,
} from "../vscode/message";
import { getPackageJson } from "../packageJson";
import type { PackageConfig } from "@ap/types/config";
import { read, ReadMode, writeFile } from "../fs";
import { tempPath } from "../tempPath";
import path from "path";
import { arenaErrorMsg } from "@ap/util/vscode/errorMsg";
import { openDiffView } from "../vscode/codeDiff";
import { createTempFile } from "../vscode/tempFile";
/**
 * 检查并更新 TypeScript 定义文件 ClientAPI.d.ts 和 GameAPI.d.ts。
 * 这个函数首先从 package.json 中读取配置，确定客户端和服务器 API 定义文件的路径。
 * 然后，它读取这些文件的内容，并与远程版本进行比较。如果存在差异，它将更新文件。
 */
export default async function checkDts(isShowMsg?: boolean): Promise<void> {
  try {
    // 尝试获取 package.json 中的文件配置，用于确定 API 定义文件的位置。
    const arenaProFileConfig =
      await getPackageJson<PackageConfig["file"]>("file");
    // 如果没有配置，則直接返回。
    if (!arenaProFileConfig) {
      return;
    }

    // 验证并清理客户端和服务器的 API 路径。
    const clientAPIPath = validateAndSanitizePath(
      arenaProFileConfig.typescript.client.base || "./client",
    );
    const serverAPIPath = validateAndSanitizePath(
      arenaProFileConfig.typescript.server.base || "./server",
    );
    // 如果路径无效，打印错误并返回。
    if (!clientAPIPath || !serverAPIPath) {
      console.error("Invalid file path.");
      return;
    }

    // 根据路径获取客户端和服务器 API 定义文件的完整路径。
    const pathG = tempPath;
    if (!pathG) {
      if (isShowMsg) {
        showErrorMessage(
          arenaErrorMsg.FAILED_TO_PULL_THE_CLOUD_SERVER_GOD_ISLAND_DTS_UNABLE_TO_DETECT_UPDATES,
        );
      }

      return;
    }
    const clientAPIFilePath = path.join(
      pathG,
      clientAPIPath + "/types/ClientAPI.d.ts",
    );
    const gameAPIFilePath = path.join(
      pathG,
      serverAPIPath + "/types/GameAPI.d.ts",
    );
    // 如果文件路径不存在，直接返回。
    if (!gameAPIFilePath || !clientAPIFilePath) {
      if (isShowMsg) {
        showErrorMessage(
          arenaErrorMsg.SHENJIMA_SERVERCLIENT_DTS_DOES_NOT_EXIST_AND_CANNOT_DETECT_UPDATES,
        );
      }

      return;
    }

    // 同时读取客户端和服务器的 API 定义文件内容。
    const [gameAPIText, clientAPIText] = await Promise.all([
      read(gameAPIFilePath, { mode: ReadMode.READ }),
      read(clientAPIFilePath, { mode: ReadMode.READ }),
    ]);

    // 获取远程的 API 定义数据。
    const apiData = await fetchApiData();
    // 如果存在差异，更新客户端和服务器的 API 定义文件。
    if (gameAPIText) {
      await updateFileIfNeeded(
        gameAPIFilePath,
        gameAPIText,
        apiData.gameAPI,
        "服务端",
        isShowMsg,
      );
    }
    if (clientAPIText) {
      await updateFileIfNeeded(
        clientAPIFilePath,
        clientAPIText,
        apiData.clientAPI,
        "客户端",
        isShowMsg,
      );
    }
  } catch (error) {
    // 捕获并打印任何错误。
    console.error("拉取d.ts失败:", error);
  }
}

/**
 * 从远程获取最新的 API 定义数据。
 * @returns 包含客户端和服务器 API 定义的对象。
 */
async function fetchApiData(): Promise<{ gameAPI: string; clientAPI: string }> {
  const data = { gameAPI: "", clientAPI: "" };
  const urls = ["GameAPI.d.ts", "ClientAPI.d.ts"];
  for (const url of urls) {
    // 尝试从远程获取每个 API 定义文件的内容。
    const response = await nGet<string>({
      url: "https://gitee.com/box3lab/arena_dts/raw/master/" + url,
    });
    if (response) {
      // 根据文件名将内容分配给相应的属性。
      data[url.includes("Game") ? "gameAPI" : "clientAPI"] = response;
    }
  }
  return data;
}

/**
 * 如果文件内容与远程内容不同，则更新文件。
 * @param filePath 文件路径。
 * @param fileText 当前文件内容。
 * @param remoteText 远程文件内容。
 * @param id 文件类型标识（客户端或服务器）。
 */
async function updateFileIfNeeded(
  filePath: string,
  fileText: string | Buffer,
  remoteText: string,
  id: string,
  isShowMsg?: boolean,
): Promise<void> {
  // 如果当前内容与远程内容不同，则更新文件。
  if (remoteText && fileText !== remoteText) {
    await writeFile(filePath, remoteText);

    if (await openDiffMsg(`神岛${id} d.ts有新版本，已自动同步。`)) {
      const originalDoc = await createTempFile(
        fileText as string,
        id + ".d.ts",
      );
      const modifiedFileUri = vscode.Uri.file(filePath);
      const title = `${id}d.ts更新预览（左：旧版，右：最新版）`;
      openDiffView(originalDoc, modifiedFileUri, title);
    }
  } else {
    if (isShowMsg) {
      showInformationMessage(`神岛${id} d.ts暂无更新`);
    }
  }
}

/**
 * 验证并清理文件路径。
 * @param path 输入的文件路径。
 * @returns 如果路径有效，则返回清理后的路径；否则返回 null。
 */
function validateAndSanitizePath(path: string): string | null {
  // 如果路径为空，则返回 null。
  return path ? path : null;
}
